#include "server.h"

Server::Server(){
	serverDataLock = new ServerLock("ServerDataLock",0,this);
	serverDataLock->SCreateLock();
	serverLockIndex = 1;
	readyPktQueue = new List();
	readyMailQueue = new List();
	monVar = new int[MAX_NUM_MONVARS];
	char* name;
	for (int i=1; i<(MAX_NUM_SERVLOCKS+1); i++){
		name = new char [20];
		sprintf(name,"ServerLock%d",i);
		serverLock[i] = new ServerLock(name,i,this);
	}
	for (int i=0; i<(MAX_NUM_SERVCONDS); i++){
		name = new char [20];
		sprintf(name,"ServerCond%d",i);
		serverCond[i] = new ServerCondition(name,i,this);
	}
	for(int i=0; i<(MAX_NUM_MONVARS); i++){
		monVar[i] = 0;
	}
}
Server::~Server(){
	
}
    
void Server::ReceiveMessage(int type, int from, int lock, int cond, int ind, int val){
	switch (type) {
		default:
			printf("Unknown type - shutting down.\n");
		//user prog requested acquire
		case LOCK_ACQUIRE: 
			printf("Addr %d requested lock acquire for lock %d \n",from,lock);
			if (lock == SERVERDATALOCK){
				serverDataLock->SAcquire(from);
			}
			else{
				if (lock <= MAX_NUM_SERVLOCKS && lock > 0){
					serverLock[lock]->SAcquire(from);
				}
			}
		break;
		//user prog requested release
		case LOCK_RELEASE:
			printf("Addr %d requested lock release for lock %d \n",from,lock);
			if (lock == SERVERDATALOCK){
				serverDataLock->SRelease(from, false);
			}
			else{
				if (lock <= MAX_NUM_SERVLOCKS && lock > 0){
					serverLock[lock]->SRelease(from, false);
				}
			}
		break;
		case LOCK_ISHELDBYCURRENT://server
			//not implemented for proj 3
			printf("Lock isHeldByCurrent requested\n");
		break;
		//user prog requested wait
		case COND_WAIT:
			printf("Addr %d requested cond wait for lock %d cond %d\n",from,lock,cond);
			if (lock == SERVERDATALOCK){
				serverCond[cond]->SWait(serverDataLock, from);
			}
			else{
				if ((lock <= MAX_NUM_SERVLOCKS && lock > 0) && (cond < MAX_NUM_SERVCONDS && lock >= 0)){
					serverCond[cond]->SWait(serverLock[lock], from);
				}
			}
		break;
		//user prog requested signal
		case COND_SIGNAL:
			printf("Addr %d requested cond signal for lock %d cond %d\n",from,lock,cond);
			if (lock == SERVERDATALOCK){
				serverCond[cond]->SSignal(serverDataLock, from);
			}
			else{
				if ((lock <= MAX_NUM_SERVLOCKS && lock > 0) && (cond < MAX_NUM_SERVCONDS && lock >= 0)){
					serverCond[cond]->SSignal(serverLock[lock], from);
				}
			}
		break;
		//user prog requested broadcast
		case COND_BROADCAST:
			printf("Addr %d requested cond broadcast for lock %d cond %d\n",from,lock,cond);
			if (lock == SERVERDATALOCK){
				serverCond[cond]->SBroadcast(serverDataLock, from);
			}
			else{
				if ((lock <= MAX_NUM_SERVLOCKS && lock > 0) && (cond < MAX_NUM_SERVCONDS && lock >= 0)){
					serverCond[cond]->SBroadcast(serverLock[lock], from);
				}
			}
		break;
		//user prog requested to update MV
		case UPDATE_MV:
			printf("Addr %d requested to update monVar[%d]=%d to monVar[%d]=%d\n",from,ind,monVar[ind],ind,val);
			monVar[ind]=val;
			AddToReadyQueue(from);
		break;
		//user prog requested to retreive MV
		case RETRIEVE_MV:
			printf("Addr %d requested to retreive monVar[%d]=%d\n",from,ind,monVar[ind]);
			AddToReadyQueue(from);
		break;
		case CREATE_LOCK:
			if(lock < 0 || lock > MAX_NUM_SERVLOCKS){
				printf("Lock %d is out of bounds (only locks 0-10 are valid)\n",lock);
			}
			else{
				printf("Addr %d requested to create lock[%d]\n",from,lock);
				if (lock == SERVERDATALOCK){
					printf("ServerDataLock already created\n");
				}
				else{
					serverLock[lock]->SCreateLock();
				}
				AddToReadyQueue(from);
			}
		break;
	}
}

void Server::AddToReadyQueue(int to){
	readyPktQueue->Append((void*)to);
}

int Server::GetNextPktDest(){
	if (readyPktQueue->IsEmpty()){
		return -1;
	}
	else {
		return (int)readyPktQueue->Remove();
	}
}

int Server::GetMV(int index){
	return monVar[index];
}
